package controllers

import java.io.{File, FilenameFilter}
import java.nio.file.Files

import command.CommandExec
import dao._
import javax.inject.Inject
import org.apache.commons.io.FileUtils
import play.api.mvc._
import play.api.libs.concurrent.Execution.Implicits._
import play.api.libs.json.Json
import utils.Utils

import scala.collection.JavaConverters._
import scala.collection.mutable.ArrayBuffer
import models.Tables._
import org.apache.commons.lang3.StringUtils
import play.api.data._
import play.api.data.Forms._
import tool.Pojo.{CommandData, UserRequest}
import tool.{FormTool, Tool}

import scala.concurrent.{ExecutionContext, Future}
import implicits.Implicits._

class UserAction @Inject()(val parser: BodyParsers.Default)(implicit val executionContext: ExecutionContext)
  extends ActionBuilder[UserRequest, AnyContent]
    with ActionTransformer[Request, UserRequest] {
  def transform[A](request: Request[A]) = Future.successful {
    new UserRequest(request)
  }
}

/**
 * Created by yz on 2018/5/24
 */
class ProteinController @Inject()(proteinDealDao: ProteinDealDao, tool: Tool, projectDao: ProjectDao,
                                  groupDao: GroupDao, userAction: UserAction)(
                                   implicit val modeDao: ModeDao
                                 )  extends Controller {

  def toIndex = Action.async { implicit request =>
    val data = tool.projectIdForm.bindFromRequest().get
    projectDao.selectById(data.projectId).map { x =>
      Redirect(routes.ProteinController.redirectIndex(data.projectId)).
        withSession(request.session + ("projectId" -> data.projectId.toString) + ("projectName" -> x.projectname))

    }
  }

  def redirectIndex(projectId: Int) = Action.async { implicit request =>
    proteinDealDao.selectByProjectId(projectId).map { x =>
      Ok(views.html.index(x))
    }
  }

  def getSampleNames = Action { implicit request =>
    val file = tool.getDbFile
    val lines = FileUtils.readLines(file).asScala
    val sampleNames = lines.head.split("\t").drop(1)
    Ok(Json.obj("sampleNames" -> sampleNames))
  }

  def getData = Action { implicit request =>
    val file = tool.getDealFile
    val json = Utils.getDataJson(file)
    Ok(json)
  }


  def plotExp = Action { implicit request =>
    val geneId = tool.geneIdForm.bindFromRequest().get.geneId
    val dataFile = tool.getDealFile
    val tmpDir = Tool.createTempDirectory("tmpDir")
    FileUtils.copyFileToDirectory(dataFile, tmpDir)
    val pyFile = new File(Tool.pyPath, "barChart.py")
    val command =
      s"""
         |python2 ${pyFile.unixPath}  -g  ${geneId.mkString("\"", "", "\"")}
         |""".stripMargin.conda("py27")
    val execCommand = CommandExec().exec { b =>
      CommandData(tmpDir, command)
    }
    if (execCommand.isSuccess) {
      val divFile = new File(tmpDir, "div.txt")
      val divStr = FileUtils.readFileToString(divFile)
      val json = Json.obj("div" -> divStr)
      Tool.deleteDirectory(tmpDir)
      Ok(json)
    } else {
      Tool.deleteDirectory(tmpDir)
      Ok(Json.obj("valid" -> "false", "message" -> execCommand.errorInfo))
    }
  }

  def dataDeal = Action.async { implicit request =>
    var dbFile = tool.getDbFile
    val tmpDir = Files.createTempDirectory("tmpDir").toFile
    //      val tmpDir = new File("E:\\tmp")
    val dataFile = new File(tmpDir, "data.txt")
    FileUtils.copyFileToDirectory(dbFile, tmpDir)
    val dataDeal = tool.dataDealForm.bindFromRequest.get
    val delete = tool.deleteForm.bindFromRequest().get
    val emptyCommandData = CommandData(tmpDir, List(""))
    val dataDealCommandData = if (dataDeal.delete.isDefined) {
      val rFile = new File(Tool.rPath, "evDelete.R")
      val command =
        s"""
           |Rscript  --restore --no-save  ${rFile.unixPath} --c  ${delete.iqr}
           |""".stripMargin.conda()
      CommandData(tmpDir, List(command))
    } else emptyCommandData
    val replace = tool.replaceForm.bindFromRequest().get
    val replaceCommandData = if (dataDeal.replace.isDefined) {
      if (replace.replaceMethod == "最小正数的倍数") {
        Utils.replaceByRate(dataFile, replace.rate)
        emptyCommandData
      } else if (replace.replaceMethod == "指定某个值") {
        Utils.replaceByValue(dataFile, replace.assignValue)
        emptyCommandData
      } else {
        Utils.relace0byNan(dataFile)
        val rFile = new File(Tool.rPath, "kNN.R")
        val command =
          s"""
             |Rscript --restore --no-save ${rFile.unixPath} --k ${replace.kValue}
             |""".stripMargin.conda()
        CommandData(tmpDir, List(command))
      }
    } else emptyCommandData
    val normal = tool.normalForm.bindFromRequest().get
    val commandExec = CommandExec().exec { b =>
      dataDealCommandData
    }.exec { b =>
      replaceCommandData
    }.map { b =>
      if (dataDeal.normal.isDefined) {
        val normalMethod = normal.normalMethod.get
        if (normalMethod.size == 2) {
          Utils.qcNormal(dataFile, normal.colName)
          Utils.peakAreaNormal(dataFile, normal.coefficient)
        } else if (normalMethod.sum == 1) {
          Utils.qcNormal(dataFile, normal.colName)
        } else {
          Utils.peakAreaNormal(dataFile, normal.coefficient)
        }
      }
    }

    val dealFile = tool.getDealFile
    FileUtils.copyFile(dataFile, dealFile)
    Utils.deleteDirectory(tmpDir)
    if (commandExec.isSuccess) {
      val projectId = tool.getProjectId
      val row = ProteindealRow(projectId, dataDeal.delete, delete.iqr, dataDeal.replace, replace.replaceMethod, replace.rate,
        replace.assignValue, replace.kValue, dataDeal.normal, normal.normalMethod.map(_.sum), normal.colName,
        normal.coefficient)
      proteinDealDao.insertOrUpdate(row).map { x =>
        val json = Utils.getDataJson(dealFile)
        Ok(json)
      }
    } else {
      Future.successful(Ok(Json.obj("valid" -> "false", "message" -> commandExec.errorInfo)))
    }

  }

  def getAllGroup = Action.async { implicit request =>
    val projectId = tool.getProjectId
    groupDao.selectAll(projectId).map { x =>
      val array = getArrayByGroups(x)
      Ok(Json.toJson(array))
    }
  }

  def getArrayByGroups(x: Seq[GroupRow]) = {
    x.map { y =>
      val contentStr = y.content.split(";").map { x =>
        val sampleNameStr = x.split(":")(1).split(",").mkString("&nbsp;")
        x.split(":")(0) + (":&nbsp;") + sampleNameStr
      }.mkString("<br>")

      val groupNum = Utils.getGroupNum(y.content)
      val relationStr = if (groupNum == 2) {
        val isSameSampleNum = y.content.split(";").map(_.split(":")(1).split(",").size).toSet.size == 1
        if (!isSameSampleNum) {
          "无"
        } else if (y.relation.isDefined) {
          y.relation.get.split(";").map { x =>
            val sampleName1 = x.split("<->")(0)
            val sampleName2 = x.split("<->")(1)
            sampleName1 + "&nbsp;<i class='fa fa-arrows-h'></i>&nbsp;" + sampleName2
          }.mkString("<br>")
        } else {
          "<a title='构建配对样品关系' onclick=\"addRelation('" + y.id + "')\" style='cursor: pointer;'><span><em class='fa fa-plus'></em></span></a>"
        }
      } else {
        "无"
      }

      val deleteStr = "<a title='删除' onclick=\"deleteGrouping('" + y.id + "')\" style='cursor: pointer;'><span><em class='fa fa-close'></em></span></a>"
      Json.obj(
        "groupname" -> y.groupname, "content" -> contentStr, "operate" -> deleteStr, "relation" -> relationStr
      )
    }
  }

  val idForm = Form(
    single(
      "id" -> number
    )
  )

  def deleteGroupById = Action.async { implicit request =>
    val id = idForm.bindFromRequest().get
    groupDao.deleteById(id).map { x =>
      Redirect(routes.ProteinController.getAllGroup())
    }
  }

  def selectGroupById = Action.async { implicit request =>
    val id = idForm.bindFromRequest().get
    groupDao.selectById(id).map { x =>
      val group1Name = x.content.split(";")(0).split(":")(0)
      val group2Name = x.content.split(";")(1).split(":")(0)
      val group1SampleNames = x.content.split(";")(0).split(":")(1).split(",")
      val group2SampleNames = x.content.split(";")(1).split(":")(1).split(",")
      Ok(Json.obj("groupingName" -> x.groupname, "group1Name" -> group1Name, "group2Name" -> group2Name,
        "group1SampleNames" -> group1SampleNames, "group2SampleNames" -> group2SampleNames))
    }
  }

  def addGroup = Action.async { implicit request =>
    val data = tool.groupForm.bindFromRequest().get
    val groupNames = data.groupNames
    val disGroupNames = groupNames.distinct
    val errorGroupNames = groupNames.diff(disGroupNames).distinct
    var valid = "true"
    var message = ""
    if (errorGroupNames.nonEmpty) {
      valid = "false"
      message = "组名： " + errorGroupNames.mkString("、") + " 重复！"
    }
    val projectId = tool.getProjectId
    val group = Utils.execFuture(groupDao.selectByGroupName(projectId, data.groupingName))
    if (group.isDefined) {
      valid = "false"
      message = "分组名已存在！"
    }

    if (valid == "true") {
      val sampleNames = data.sampleNames
      val content = groupNames.zip(sampleNames).map { case (groupName, sampleNames) =>
        groupName + ":" + sampleNames
      }.mkString(";")
      val row = GroupRow(0, projectId, data.groupingName, content)
      groupDao.insert(row).flatMap(_ => groupDao.selectAll(projectId)).map { x =>
        val array = getArrayByGroups(x)
        Ok(Json.toJson(array))
      }
    } else {
      Future.successful(Ok(Json.obj("valid" -> valid, "message" -> message)))
    }
  }

  def updateRelation = Action.async { implicit request =>
    val data = tool.relationForm.bindFromRequest().get
    val group1SampleNames = data.group1SampleNames
    val group2SampleNames = data.group2SampleNames
    val projectId = tool.getProjectId
    val relation = group1SampleNames.zip(group2SampleNames).map { case (group1SampleName, group2SampleName) =>
      group1SampleName + "<->" + group2SampleName
    }.mkString(";")
    groupDao.update(data.id, Some(relation)).flatMap(_ => groupDao.selectAll(projectId)).map { x =>
      val array = getArrayByGroups(x)
      Ok(Json.toJson(array))
    }
  }

  def groupBefore = Action { implicit request =>
    val file = tool.getDbFile
    val lines = FileUtils.readLines(file).asScala
    val sampleNames = lines.head.split("\t").drop(1)
    Ok(views.html.group(sampleNames))
  }

  def plotDiffExp = Action { implicit request =>
    val geneId = tool.geneIdForm.bindFromRequest().get.geneId
    val diffData = tool.diffForm.bindFromRequest().get
    val dataFile = tool.getDealFile
    val tmpDir = Files.createTempDirectory("tmpDir").toFile
    FileUtils.copyFileToDirectory(dataFile, tmpDir)
    tool.productGroupFile(diffData.groupName, tmpDir)
    val pyFile = new File(Tool.pyPath, "diffBarChart.py")
    val command =
      s"""
         |python2 ${pyFile.unixPath}  -g  ${geneId.mkString("\"", "", "\"")}
         |""".stripMargin.conda("py27")
    val execCommand = CommandExec().exec { b =>
      CommandData(tmpDir, command)
    }
    if (execCommand.isSuccess) {
      val divFile = new File(tmpDir, "div.txt")
      val divStr = FileUtils.readFileToString(divFile)
      val json = Json.obj("div" -> divStr)
      Tool.deleteDirectory(tmpDir)
      Ok(json)
    } else {
      Tool.deleteDirectory(tmpDir)
      Ok(Json.obj("valid" -> "false", "message" -> execCommand.errorInfo))
    }
  }

  def getAllGroupNum2Names = Action.async { implicit request =>
    val projectId = tool.getProjectId
    groupDao.selectAll(projectId).map { x =>
      val groupNames = x.filter { y =>
        Utils.getGroupNum(y.content) == 2
      }.map(_.groupname)
      Ok(Json.toJson(groupNames))
    }
  }

  def checkRelation = Action.async { implicit request =>
    val groupName = tool.groupNameForm.bindFromRequest().get.groupName
    val projectId = tool.getProjectId
    groupDao.selectByGroupName(projectId, groupName).map { x =>
      val relation = if (x.get.relation.isDefined) "True" else "False"
      Ok(relation)
    }
  }

  def differenceAna = Action.async { implicit request =>
    val projectId = tool.getProjectId
    val data = tool.tTestForm.bindFromRequest.get
    groupDao.selectByGroupName(projectId, data.groupName).map(_.get).
      map { group =>
        val dataFile = tool.getDealFile
        val tmpDir = Tool.createTempDirectory("tmpDir")
        FileUtils.copyFileToDirectory(dataFile, tmpDir)
        val groupFile = new File(tmpDir, "group.txt")
        val sampleGroup = collection.mutable.LinkedHashMap[String, String]()
        group.content.split(";").foreach { x =>
          val lines = x.split(":")
          lines(1).split(",").foreach { sam =>
            sampleGroup += (sam -> lines(0))
          }
        }
        val groupBuffer = if (data.paired == "T") {
          group.relation.get.split(";").flatMap { x =>
            val columns = x.split("<->")
            ArrayBuffer(columns(0) + "\t" + sampleGroup(columns(0)), columns(1) + "\t" + sampleGroup(columns(1)))
          }.toBuffer
        } else {
          sampleGroup.map { case (sam, groupName) =>
            sam + "\t" + groupName
          }.toBuffer
        }
        FileUtils.writeLines(groupFile, groupBuffer.asJava)
        val rFile = new File(Tool.rPath, "proteinDifferenceAna.R")
        val pyFile = new File(Tool.pyPath, "volcano.py")
        val command =
          s"""
             |${"Rscript".condaPath()} --restore --no-save ${rFile.unixPath}  --paired ${data.paired}  --pCutoff  ${data.pCutoff}  --qCutoff  ${data.qCutoff}  --m  ${data.method}  --l ${data.logCutoff}  --ve   ${data.varEqual}
             |""".stripMargin
        val command1 =
          s"""
             |python2  ${pyFile.unixPath} --pCutoff  ${data.pCutoff}  --qCutoff  ${data.qCutoff} --l  ${data.logCutoff}
             |""".stripMargin.conda("py27")
        val execCommand = CommandExec().exec { b =>
          CommandData(tmpDir, List(command, command1))
        }
        if (execCommand.isSuccess) {
          val file = new File(tmpDir, "result.txt")
          val (columnNames, array) = Utils.getInfoByFile(file)
          val logFcs = FileUtils.readLines(file).asScala.drop(1).map(_.split("\t")(5))
          val keggStr = array.map(_ ("geneId")).zip(logFcs).map { case (geneId, log2Fc) =>
            s"${geneId}\t${log2Fc}"
          }.mkString("\n")
          val geneIdStr = Utils.lfJoin(array.map(_ ("geneId")).toList)
          val divFile = new File(tmpDir, "div.txt")
          val divStr = FileUtils.readFileToString(divFile) + Utils.pyScript
          val json = Json.obj("columnNames" -> columnNames, "array" -> array, "div" -> divStr,
            "geneIdStr" -> geneIdStr, "keggStr" -> keggStr)
          Tool.deleteDirectory(tmpDir)
          Ok(json)
        } else {
          Tool.deleteDirectory(tmpDir)
          Ok(Json.obj("valid" -> "false", "message" -> execCommand.errorInfo))
        }
      }
  }

  def differenceAnaBefore = Action { implicit request =>
    Ok(views.html.differenceAna())
  }

  def goBarPlot = Action { implicit request =>
    val data = tool.goBarForm.bindFromRequest().get
    val tmpDir = Files.createTempDirectory("tmpDir").toFile
    val buffer = ArrayBuffer(s"ID\tdata\tkind")
    buffer ++= data.terms.zipWithIndex.map { case (v, i) =>
      s"${v}\t${data.datas(i)}\t${data.kinds(i)}"
    }
    FileUtils.writeLines(new File(tmpDir, "deal.txt"), buffer.asJava)
    //    FileUtils.writeLines(new File("E:\\testData\\deal.txt"), buffer.asJava)
    val pyFile = new File(Tool.pyPath, "goBarChart.py")
    val command =
      s"""
         |python2 ${pyFile.unixPath}
         |""".stripMargin.conda("py27")
    val execCommand = CommandExec().exec { b =>
      CommandData(tmpDir, List(command))
    }
    if (execCommand.isSuccess) {
      val divFile = new File(tmpDir, "div.txt")
      val divStr = FileUtils.readFileToString(divFile) + Utils.pyScript
      val json = Json.obj("div" -> divStr)
      Tool.deleteDirectory(tmpDir)
      Ok(json)
    } else {
      Tool.deleteDirectory(tmpDir)
      Ok(Json.obj("valid" -> "false", "message" -> execCommand.errorInfo))
    }
  }

  def goPBarPlot = Action { implicit request =>
    val data = tool.goBarForm.bindFromRequest().get
    val tmpDir = Files.createTempDirectory("tmpDir").toFile
    val buffer = ArrayBuffer(s"ID\tdata\tkind")
    buffer ++= data.terms.zipWithIndex.map { case (v, i) =>
      s"${v}\t${data.datas(i)}\t${data.kinds(i)}"
    }
    FileUtils.writeLines(new File(tmpDir, "deal.txt"), buffer.asJava)
    //    FileUtils.writeLines(new File("E:\\testData\\deal.txt"), buffer.asJava)
    val pyFile = new File(Tool.pyPath, "goPBarChart.py")
    val command =
      s"""
         |python2  ${pyFile.unixPath}
         |""".stripMargin.conda("py27")
    val execCommand = CommandExec().exec { b =>
      CommandData(tmpDir, List(command))
    }
    if (execCommand.isSuccess) {
      val divFile = new File(tmpDir, "div.txt")
      val divStr = FileUtils.readFileToString(divFile) + Utils.pyScript
      val json = Json.obj("div" -> divStr)
      Tool.deleteDirectory(tmpDir)
      Ok(json)
    } else {
      Tool.deleteDirectory(tmpDir)
      Ok(Json.obj("valid" -> "false", "message" -> execCommand.errorInfo))
    }
  }

  def pie = Action { implicit request =>
    val data = tool.barForm.bindFromRequest().get
    val tmpDir = Files.createTempDirectory("tmpDir").toFile
    val buffer = ArrayBuffer(s"ID\t${data.terms.mkString("\t")}")
    buffer += s"data\t${data.datas.mkString("\t")}"
    FileUtils.writeLines(new File(tmpDir, "deal.txt"), buffer.asJava)
    val pyFile = new File(Tool.pyPath, "pie.py")
    val command =
      s"""
         |python2 ${pyFile.unixPath}
         |""".stripMargin.conda("py27")
    val execCommand = CommandExec().exec { b =>
      CommandData(tmpDir, List(command))
    }
    if (execCommand.isSuccess) {
      val divFile = new File(tmpDir, "div.txt")
      val divStr = FileUtils.readFileToString(divFile) + Utils.pyScript
      val json = Json.obj("div" -> divStr)
      Tool.deleteDirectory(tmpDir)
      Ok(json)
    } else {
      Tool.deleteDirectory(tmpDir)
      Ok(Json.obj("valid" -> "false", "message" -> execCommand.errorInfo))
    }
  }

  def getFirst10GeneIdByLf = Action { implicit request =>
    val dataFile = tool.getDealFile
    val lines = FileUtils.readLines(dataFile).asScala.drop(1)
    val geneIds = lines.map(_.split("\t")(0)).take(10)
    val geneIdStr = geneIds.mkString("\n")
    Ok(geneIdStr)
  }

  def getGeneIds = Action { implicit request =>
    val file = tool.getDbFile
    val lines = FileUtils.readLines(file).asScala
    val geneIds = lines.drop(1).map(_.split("\t")(0))
    Ok(Json.obj("geneIds" -> geneIds))
  }

  def goEnrich = Action { implicit request =>
    val userPath = tool.getProjectIdDir
    val data = tool.goEnrichForm.bindFromRequest.get
    val tmpDir = Tool.createTempDirectory("tmpDir")
    val diffFile = new File(tmpDir, "diff.txt")
    val buffer = Utils.dealGeneIds(data.geneId)
    FileUtils.writeLines(diffFile, buffer.asJava)
    val outFile = new File(tmpDir, "out.txt")
    val enrichFile = new File(Tool.binPath, "goatools-0.5.7/scripts/find_enrichment.py")
    val geneListFile = new File(userPath, "list.txt")
    val annoFile = new File(userPath, "go.txt")
    val command =
      s"""
         |python2 ${enrichFile.unixPath}  --alpha ${data.twa}  --pval  ${data.ewa} --output  ${outFile.unixPath}   ${diffFile.unixPath}   ${geneListFile.unixPath}  ${annoFile.unixPath}
         |""".stripMargin.conda("py27")
    val execCommand = CommandExec().exec { b =>
      CommandData(tmpDir, List(command))
    }
    if (execCommand.isSuccess) {
      val buffer = FileUtils.readLines(outFile).asScala.drop(1)
      val jsons = buffer.filter(_.split("\t")(1) == "e").map { x =>
        val columns = x.split("\t")
        val pu = columns(5).toDouble.formatted("%.3f").toString
        Json.obj("id" -> columns(0), "enrichment" -> columns(1), "description" -> columns(2), "ratio_in_study" -> columns(3),
          "ratio_in_pop" -> columns(4), "p_uncorrected" -> pu, "p_bonferroni" -> columns(6), "p_holm" -> columns(7),
          "p_sidak" -> columns(8), "p_fdr" -> columns(9), "namespace" -> columns(10), "genes_in_study" -> columns(11))
      }
      Tool.deleteDirectory(tmpDir)
      Ok(Json.toJson(jsons))
    } else {
      Tool.deleteDirectory(tmpDir)
      Ok(Json.obj("valid" -> "false", "message" -> execCommand.errorInfo))
    }
  }

  def goEnrichBefore = Action { implicit request =>
    Ok(views.html.goEnrich(None))
  }

  def barPlot = Action { implicit request =>
    val data = tool.barForm.bindFromRequest().get
    val tmpDir = Files.createTempDirectory("tmpDir").toFile
    val buffer = ArrayBuffer(s"ID\t${data.terms.mkString("\t")}")
    buffer += s"data\t${data.datas.mkString("\t")}"
    FileUtils.writeLines(new File(tmpDir, "deal.txt"), buffer.asJava)
    val pyFile = new File(Tool.pyPath, "myBarChart.py")
    val command =
      s"""
         |python2 ${pyFile.unixPath}
         |""".stripMargin.conda("py27")
    val execCommand = CommandExec().exec { b =>
      CommandData(tmpDir, List(command))
    }
    if (execCommand.isSuccess) {
      val divFile = new File(tmpDir, "div.txt")
      val divStr = FileUtils.readFileToString(divFile) + Utils.pyScript
      val json = Json.obj("div" -> divStr)
      Tool.deleteDirectory(tmpDir)
      Ok(json)
    } else {
      Tool.deleteDirectory(tmpDir)
      Ok(Json.obj("valid" -> "false", "message" -> execCommand.errorInfo))
    }
  }

  def pBarPlot = Action { implicit request =>
    val data = tool.barForm.bindFromRequest().get
    val tmpDir = Files.createTempDirectory("tmpDir").toFile
    val buffer = ArrayBuffer(s"ID\t${data.terms.mkString("\t")}")
    buffer += s"data\t${data.datas.mkString("\t")}"
    FileUtils.writeLines(new File(tmpDir, "deal.txt"), buffer.asJava)
    val pyFile = new File(Tool.pyPath, "pBarChart.py")
    val command =
      s"""
         |python2  ${pyFile.unixPath}
         |""".stripMargin.conda("py27")
    val execCommand = CommandExec().exec { b =>
      CommandData(tmpDir, List(command))
    }
    if (execCommand.isSuccess) {
      val divFile = new File(tmpDir, "div.txt")
      val divStr = FileUtils.readFileToString(divFile) + Utils.pyScript
      val json = Json.obj("div" -> divStr)
      Tool.deleteDirectory(tmpDir)
      Ok(json)
    } else {
      Tool.deleteDirectory(tmpDir)
      Ok(Json.obj("valid" -> "false", "message" -> execCommand.errorInfo))
    }
  }

  def geneIdCheck(implicit ec: ExecutionContext) = new ActionFilter[UserRequest] {

    override protected def executionContext: ExecutionContext = ec

    override protected def filter[A](request: UserRequest[A]) = Future.successful {
      val data = tool.keggEnrichForm.bindFromRequest()(request).get
      val lines = data.geneId.split("\n").map(_.trim).distinct.toBuffer
      val array = lines.map(_.split("\\s+"))
      val b = array match {
        case x if x.exists(_.size > 2) => false
        case x if x.exists(_.size == 2) && x.forall(_.size == 2) =>
          val values = array.map(_ (1))
          if (!values.forall(x => Utils.isDouble(x))) {
            false
          } else true
        case x if x.exists(_.size == 2) && !x.forall(_.size == 2) => false
        case _ => true
      }
      if (!b) {
        Some(Ok(Json.obj("valid" -> "false", "message" -> "蛋白ID格式不正确")))
      } else {
        None
      }
    }
  }

  def keggEnrich = userAction.andThen(geneIdCheck) { implicit request =>
    val userPath = tool.getProjectIdDir
    val data = tool.keggEnrichForm.bindFromRequest.get
    val tmpDir = Tool.createTempDirectory("tmpDir")
    val diffFile = new File(tmpDir, "diff.txt")
    val lines = data.geneId.split("\n").map(_.trim).distinct.toBuffer
    val geneIdBuffer = lines.map(_.split("\\s+")(0))
    val geneIdlog2FcMap = if (lines(0).split("\\s+").size == 2) {
      lines.map { x =>
        (x.split("\\s+")(0), x.split("\\s+")(1).toDouble)
      }.toMap
    } else Map[String, Double]()
    FileUtils.writeLines(diffFile, geneIdBuffer.asJava)
    val outFile = new File(tmpDir, "out.txt")
    val identifyFile = new File(Tool.binPath, "identify.pl")
    val geneListFile = new File(userPath, "list.txt")
    val annoFile = new File(userPath, "kegg.txt")
    val geneIdKMap = FileUtils.readLines(annoFile).asScala.map { x =>
      (x.split("\t")(0), x.split("\t")(1))
    }.toMap
    val kGeneIdMap = geneIdKMap.filter { case (key, value) =>
      geneIdBuffer.contains(key)
    }.map { case (key, value) =>
      (value, key)
    }
    val command =
      s"""
         |dos2unix *
         |perl  ${identifyFile.unixPath}  -study  ${diffFile.unixPath}  -population  ${geneListFile.unixPath} -association  ${annoFile.unixPath}  -m  ${data.method}  -n ${data.fdr}  -c  ${data.cutoff}  -o  ${outFile.unixPath}  -maxp  ${data.pValue}
         |""".stripMargin
    val execCommand = CommandExec().exec { b =>
      CommandData(tmpDir, List(command))
    }
    if (execCommand.isSuccess) {
      val buffer = FileUtils.readLines(outFile).asScala.drop(1).filter(x => StringUtils.isNoneBlank(x))
      Tool.deleteDirectory(tmpDir)
      val jsons = buffer.map { x =>
        val columns = x.split("\t")
        val pValue = columns(5).toDouble.formatted("%.3f").toString
        val cPValue = columns(6).toDouble.formatted("%.3f").toString
        val heads = columns(8).split("\\?")
        val koHeads = heads(1).split("\\/")
        val ks = koHeads.tail
        val kStr = ks.map { k =>
          val buffer = k.split("%09")
          val kNumber = buffer(0)
          val geneId = kGeneIdMap(kNumber)
          val log2Fc = geneIdlog2FcMap.getOrElse(geneId, 2.0)
          val color = if (log2Fc > 0) {
            "red"
          } else {
            "blue"
          }
          s"${buffer(0)}%09${color}"
        }.mkString("/")
        val href = s"${heads(0)}?${koHeads(0)}/${kStr}"
        val link = s"<a href='${href}' target='_blank'>link</a>"
        Json.obj("term" -> columns(0), "database" -> columns(1), "id" -> columns(2), "inputNumber" -> columns(3),
          "backgroundNumber" -> columns(4), "pValue" -> pValue, "cPValue" -> cPValue, "input" -> columns(7),
          "hyperlink" -> link)
      }
      Ok(Json.toJson(jsons))
    } else {
      Tool.deleteDirectory(tmpDir)
      Ok(Json.obj("valid" -> "false", "message" -> execCommand.errorInfo))
    }
  }

  def keggEnrichBefore = Action { implicit request =>
    Ok(views.html.keggEnrich(None))
  }

  def keggEnrichBefore1 = Action { implicit request =>
    val data = FormTool.geneIdStrForm.bindFromRequest().get
    Ok(views.html.keggEnrich(Some(data.geneIdStr)))
  }

  def heatmap = Action { implicit request =>
    val sampleNames = tool.sampleNamesForm.bindFromRequest.get.sampleNames
    val geneIdStr = FormTool.geneIdStrForm.bindFromRequest.get.geneIdStr
    val heatmapData = tool.heatmapForm.bindFromRequest.get
    val dataFile = tool.getDealFile
    val tmpDir = Files.createTempDirectory("tmpDir").toFile
    FileUtils.copyFileToDirectory(dataFile, tmpDir)
    val rFile = new File(Tool.rPath, "dataTransform.R")
    val pyFile = new File(Tool.pyPath, "dendrogramWithHeatmap.py")
    //        val pyFile = new File(Tool.pyPath, "heatmap.py")
    val geneIds = Utils.dealGeneIds(geneIdStr)
    FileUtils.writeLines(new File(tmpDir, "gene.txt"), geneIds.asJava)
    val rCommand =
      s"""
         |Rscript --restore --no-save ${rFile.unixPath} --m  ${heatmapData.method}
         |""".stripMargin.conda()
    val command =
      s"""
         |python2 ${pyFile.unixPath} -s ${sampleNames.mkString(" ")}  -rd ${heatmapData.rowDist} -cd ${heatmapData.colDist} -rl ${heatmapData.rowCluster} -cl ${heatmapData.colCluster}
         |""".stripMargin.conda("py27")
    val execCommand = CommandExec().exec { b =>
      CommandData(tmpDir, List(rCommand, command))
    }
    if (execCommand.isSuccess) {
      val divFile = new File(tmpDir, "div.txt")
      val divStr = FileUtils.readFileToString(divFile) + Utils.pyScript
      val dataFile = new File(tmpDir, "deal.txt")
      val array = Utils.getDataJson(dataFile)
      val json = Json.obj("div" -> divStr, "json" -> array)
      Tool.deleteDirectory(tmpDir)
      Ok(json)
    } else {
      Tool.deleteDirectory(tmpDir)
      Ok(Json.obj("valid" -> "false", "message" -> execCommand.errorInfo))
    }
  }

  def heatmapBefore = Action { implicit request =>
    Ok(views.html.heatmap(None))
  }

  def getAllGroupNames = Action.async { implicit request =>
    val projectId = tool.getProjectId
    groupDao.selectAll(projectId).map { x =>
      val groupNames = x.map(_.groupname)
      Ok(Json.toJson(groupNames))
    }
  }

  def pca = Action { implicit request =>
    val projectId = tool.getProjectId
    val data = tool.pcaForm.bindFromRequest.get
    val dataFile = tool.getDealFile
    val tmpDir = Files.createTempDirectory("tmpDir").toFile
    FileUtils.copyFileToDirectory(dataFile, tmpDir)
    val rFile = new File(Tool.rPath, "pca.R")
    val group = Utils.execFuture(groupDao.selectByGroupName(projectId, data.groupName)).get
    val sampleNames = if (data.method == "hand") {
      data.sampleName.toBuffer
    } else {
      group.content.split(";").flatMap(_.split(":")(1).split(",")).toBuffer
    }
    Utils.productGroupFile(tmpDir, group.content)
    val rFile1 = new File(Tool.rPath, "dataTransform.R")
    val pyFile = new File(Tool.pyPath, "pca.py")
    //        val execCommand = Utils.callScript(tmpDir, shBuffer = ArrayBuffer(rCommand,command, command1))
    val rCommand =
      s"""
         |Rscript  --restore --no-save ${rFile1.unixPath}  --m  ${data.dtMethod}
         |Rscript --restore --no-save ${rFile.unixPath}  --s ${sampleNames.mkString(",")}
         |""".stripMargin.conda()
    val command =
      s"""
         |python2   ${pyFile.unixPath}  -m ${data.method}  -x  ${data.x}  -y  ${data.y}
         |""".stripMargin.conda("py27")
    val execCommand = CommandExec().exec { b =>
      CommandData(tmpDir, List(rCommand, command))
    }
    if (execCommand.isSuccess) {
      val divFile = new File(tmpDir, "div.txt")
      val divStr = FileUtils.readFileToString(divFile) + Utils.pyScript
      val json = Json.obj("div" -> divStr)
      Tool.deleteDirectory(tmpDir)
      Ok(json)
    } else {
      Tool.deleteDirectory(tmpDir)
      Ok(Json.obj("valid" -> "false", "message" -> execCommand.errorInfo))
    }
  }

  def pcaBefore = Action { implicit request =>
    Ok(views.html.pca())
  }

  def hCluster = Action { implicit request =>
    val data = tool.sampleNamesForm.bindFromRequest.get
    val hClusterData = tool.hClusterForm.bindFromRequest.get
    val dataFile = tool.getDealFile
    val tmpDir = Files.createTempDirectory("tmpDir").toFile
    FileUtils.copyFileToDirectory(dataFile, tmpDir)
    val rFile = new File(Tool.rPath, "dataTransform.R")
    val pyFile = new File(Tool.pyPath, "dendrogram.py")
    val rCommand =
      s"""
         |Rscript  --restore --no-save ${rFile.unixPath}  --m ${hClusterData.method}
         |""".stripMargin.conda()
    val command =
      s"""
         |python2 ${pyFile.unixPath}  -s ${data.sampleNames.mkString(" ")}  -pm ${hClusterData.sampleDist} -lm ${hClusterData.sampleCluster}
         |""".stripMargin.conda("py27")
    val execCommand = CommandExec().exec { b =>
      CommandData(tmpDir, List(rCommand, command))
    }
    if (execCommand.isSuccess) {
      val divFile = new File(tmpDir, "div.txt")
      val divStr = FileUtils.readFileToString(divFile)
      val json = Json.obj("div" -> divStr)
      Tool.deleteDirectory(tmpDir)
      Ok(json)
    } else {
      Tool.deleteDirectory(tmpDir)
      Ok(Json.obj("valid" -> "false", "message" -> execCommand.errorInfo))
    }
  }

  def hClusterBefore = Action { implicit request =>
    Ok(views.html.hCluster())
  }

  def getGroupNames = Action.async { implicit request =>
    val projectId = tool.getProjectId
    val groupingName = tool.groupingNameFom.bindFromRequest().get
    groupDao.selectByGroupName(projectId, groupingName).map { x =>
      val group = x.get
      val groupNames = Utils.getGroupNames(group.content)
      Ok(Json.toJson(groupNames))
    }
  }

  def roc = Action { implicit request =>
    val projectId = tool.getProjectId
    val data = tool.rocForm.bindFromRequest.get
    val geneIdStr = FormTool.geneIdStrForm.bindFromRequest().get.geneIdStr
    val dataFile = tool.getDealFile
    val tmpDir = Files.createTempDirectory("tmpDir").toFile
    FileUtils.copyFileToDirectory(dataFile, tmpDir)
    val group = Utils.execFuture(groupDao.selectByGroupName(projectId, data.groupingName)).get
    val groupSample = Utils.getMap(group.content)
    val pSamples = groupSample(data.pGroup)
    val buffer = FileUtils.readLines(dataFile).asScala
    val flag = ("FLAG") +: buffer.head.split("\t").drop(1).map { x =>
      if (pSamples.contains(x)) "1" else "0"
    }.toBuffer
    buffer += flag.mkString("\t")
    FileUtils.writeLines(new File(tmpDir, "deal.txt"), buffer.asJava)
    val pyFile = new File(Tool.pyPath, "roc.py")
    val geneIds = Utils.dealGeneIds(geneIdStr)
    FileUtils.writeLines(new File(tmpDir, "gene.txt"), geneIds.asJava)
    val command =
      s"""
         |python2 ${pyFile.unixPath}
         |""".stripMargin.conda("py27")
    val execCommand = CommandExec().exec { b =>
      CommandData(tmpDir, command)
    }
    if (execCommand.isSuccess) {
      val divFile = new File(tmpDir, "div.txt")
      val divStr = FileUtils.readFileToString(divFile) + Utils.pyScript
      val json = Json.obj("div" -> divStr)
      Tool.deleteDirectory(tmpDir)
      Ok(json)
    } else {
      Tool.deleteDirectory(tmpDir)
      Ok(Json.obj("valid" -> "false", "message" -> execCommand.errorInfo))
    }
  }

  def rocBefore = Action { implicit request =>
    Ok(views.html.roc(None))
  }

  def expressPattern = Action { implicit request =>
    val data = FormTool.expressPatternForm.bindFromRequest.get
    val geneIdStr = FormTool.geneIdStrForm.bindFromRequest.get.geneIdStr
    val dataFile = tool.getDealFile
    val tmpDir = Tool.createTempDirectory("tmpDir")
    FileUtils.copyFileToDirectory(dataFile, tmpDir)
    val rFile = new File(Tool.rPath, "expressPattern.R")
    val geneIds = Utils.dealGeneIds(geneIdStr)
    FileUtils.writeLines(new File(tmpDir, "gene.txt"), geneIds.asJava)
    val rCommands = List("Rscript", " --restore --no-save ", rFile.unixPath, " --s ", data.sampleNameStr,
      " --m ", data.method, " --dm ", data.sampleDist, " --cm ", data.sampleCluster)
    val cCommands = data.cMethod match {
      case "1" => List("--k ", data.k)
      case "2" => List("--kt ", data.kTree)
      case _ => List("--pt ", data.pTree)
    }
    val rCommand = (rCommands ::: cCommands).mkString(" ")
    val pyFile = new File(Tool.pyPath, "expressPattern.py")
    val rExecCommand =
      s"""
         |${rCommand}
         |""".stripMargin.conda()
    val command =
      s"""
         |python2 ${pyFile.unixPath}
         |""".stripMargin.conda("py27")
    val execCommand = CommandExec().exec { b =>
      CommandData(tmpDir, List(rExecCommand, command))
    }
    if (execCommand.isSuccess) {
      val filter = new FilenameFilter {
        override def accept(dir: File, name: String): Boolean = name.endsWith(".matrix.txt")
      }
      val files = tmpDir.listFiles(filter).sortBy(file => file.getName.split("\\.")(0))
      val subNames = files.map(_.getName.split("\\.")(0))
      val data = files.map { file =>
        val (columnNames, array) = Utils.getInfoByFile(file)
        val divFile = new File(file.getParent, file.getName.split("\\.")(0) + ".div.txt")
        val divStr = FileUtils.readFileToString(divFile) + Utils.pyScript
        Json.obj("columnNames" -> columnNames, "array" -> array, "div" -> divStr)
      }
      val json = Json.obj("data" -> data, "subNames" -> subNames)
      Tool.deleteDirectory(tmpDir)
      Ok(json)
    } else {
      Tool.deleteDirectory(tmpDir)
      Ok(Json.obj("valid" -> "false", "message" -> execCommand.errorInfo))
    }
  }

  def expressPatternBefore = Action { implicit request =>
    Ok(views.html.expressPattern(None))
  }

  def heatmapBefore1 = Action { implicit request =>
    val data = FormTool.geneIdStrForm.bindFromRequest().get
    Ok(views.html.heatmap(Some(data.geneIdStr)))
  }

  def expressPatternBefore1 = Action { implicit request =>
    val data = FormTool.geneIdStrForm.bindFromRequest().get
    Ok(views.html.expressPattern(Some(data.geneIdStr)))
  }

  def rocBefore1 = Action { implicit request =>
    val data = FormTool.geneIdStrForm.bindFromRequest().get
    Ok(views.html.roc(Some(data.geneIdStr)))
  }

  def goEnrichBefore1 = Action { implicit request =>
    val data = FormTool.geneIdStrForm.bindFromRequest().get
    Ok(views.html.goEnrich(Some(data.geneIdStr)))
  }


}
